#include "../common/config.h"

LoggerPtr gLogger = Logger::getLogger("fsroute");

int  gRunThread = 1;
static void sighandler( int sig_no )
{
    gRunThread = 0;
}

struct thread_param_t
{
    apr_thread_start_t func;
    apr_pool_t* pool;
    apr_socket_t * client;
    vector<apr_ipsubnet_t*> ipsubs;
};



bool checkPriv(thread_param_t* pParam);
esl_handle_t* GetESLHandle(esl_handle_t*, thread_param_t* pParam);
void MakeCall(string& acct, string& caller, string& called, CALL_TYPE calltype, esl_handle_t* pHandle);

void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
{

    char *data;
    va_list ap;
    int ret;

    if (level < 0 || level > 7)
    {
        level = 7;
    }

    va_start(ap, fmt);

    ret = esl_vasprintf(&data, fmt, ap);

    if (ret != -1)
    {
        LOG4CXX_TRACE(gLogger, data);
        free(data);
    }

    va_end(ap);
}


void * APR_THREAD_FUNC callback_flow(apr_thread_t*, void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    const char* pacct = esl_event_get_header(pHandle->info_event, "variable_orig_acct"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "variable_orig_caller"); //主叫号码

    const char* pcalled = esl_event_get_header(pHandle->info_event, "variable_orig_called");//被叫号码

    if (!(pacct && pcaller && pcalled))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL") << "\torigcalled=" << (pcalled ? pcalled : "NULL"));
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    string acct(pacct), caller(pcaller), called(pcalled);
    MakeCall(acct, caller, called, CALLBACK2, pHandle);
    return NULL;
}


void * APR_THREAD_FUNC conference_flow(apr_thread_t*,  void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    char* const calluuid = NULL;// strdup(esl_event_get_header(pHandle->info_event, "caller-unique-id"));
    const char* pacct = esl_event_get_header(pHandle->info_event, "variable_orig_acct"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "variable_orig_caller"); //主叫号码

    const char* pcalled = esl_event_get_header(pHandle->info_event, "variable_orig_called");//被叫号码
    const char* pin = esl_event_get_header(pHandle->info_event, "variable_pin");//被叫号码
    const char* add_conf = esl_event_get_header(pHandle->info_event, "variable_add_conf");//邀请其它人进入会议

    if (pin == NULL)
    {
        pin = "";
    }


    if (!(pacct && pcaller && pcalled))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL") << "\torigcalled=" << (pcalled ? pcalled : "NULL"));
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        free(calluuid);
        return NULL;
    }

    if (add_conf != NULL && *add_conf != 0)
    {
        string acct(pacct), caller(pcaller), called(add_conf);
        vector<call_param_t> callParam;

        if (!getCallParam(acct, caller, called, CONFERENCE, callParam))
        {
            LOG4CXX_TRACE(gLogger, "err:\taccount=" << acct << "\torigcaller=" << caller  << "\torigcalled=" << called );
            //esl_execute(pHandle, "hangup", NULL, NULL);
            esl_disconnect(pHandle);
            free(calluuid);
            return NULL;
        }

        if (callParam.begin()->nTimeout <= 0)
        {
            LOG4CXX_TRACE(gLogger, "err: timeout =" << callParam.begin()->nTimeout << "\taccount=" << acct << "\torigcaller=" << caller  << "\torigcalled=" << called );
            esl_execute(pHandle, "hangup", NULL, NULL);
            esl_disconnect(pHandle);
            free(calluuid);
            return NULL;
        }

        int n = 0;
        stringstream ss;

        for (vector<call_param_t>::iterator it = callParam.begin(); it != callParam.end(); ++it)
        {
            if (n > 0)
            {
                ss << "|";
            }

            ss << "[execute_on_answer=\'sched_hangup +" << it->nTimeout << " alloted_timeout\',orig_caller=" << called << ",orig_called=" << called << ",absolute_codec_string=\'" << it->codec << "\',origination_caller_id_number=" << it->caller << ",origination_caller_id_name=" << it->caller << "]sofia/external/" << it->called << "@" << it->server;
            n++;
        }

        ss << " &conference(" + caller + "@default)";
        esl_execute(pHandle, "set", "add_conf=", calluuid);
        string strTmp = "{calltype=6,ignore_early_media=true,proxy_media=false,jitterbuffer_msec=180,call_timeout=50,orig_acct=" + acct + "}" + ss.str() + " &conference(" + caller + "@default)\nevent-lock:true";
        n = 0;

        while (strTmp.length() > 400)
        {
            ss.str("");
            string subStr = strTmp.substr(0, 400);
            strTmp = strTmp.substr(400);
            ss << "bg" << n++ << "=" << subStr;
            esl_execute(pHandle, "set", ss.str().c_str(), calluuid);
            LOG4CXX_TRACE(gLogger, ss.str());
        }

        ss.str("");
        ss << "bg" << n << "=" << strTmp;
        esl_execute(pHandle, "set", ss.str().c_str(), calluuid);
        LOG4CXX_TRACE(gLogger, ss.str());

        free(calluuid);
        esl_disconnect(pHandle);
    }
    else
    {
        esl_execute(pHandle, "export", "calltype=6", calluuid);
        esl_execute(pHandle, "export", "proxy_media=false", calluuid);
        esl_execute(pHandle, "export", "proxy_media=false", calluuid);
        esl_execute(pHandle, "export", "jitterbuffer_msec=180", calluuid);
        esl_execute(pHandle, "set", "conference_auto_outcall_timeout=20", calluuid);
        esl_execute(pHandle, "set", "conference_auto_outcall_flags=none", calluuid);
        esl_execute(pHandle, "set", "conference_auto_outcall_profile=default", calluuid);


        string acct(pacct), caller(pcaller), called(pcalled);

        string delimiter("-");
        LOG4CXX_TRACE(gLogger, caller << "------------->" << called );
        const vector<string>& clientlist = split(called, delimiter);

        for (vector<string>::const_iterator iter = clientlist.begin(); iter != clientlist.end(); ++iter)
        {
            vector<call_param_t> callParam;

            if (!getCallParam(acct, caller, *iter, CONFERENCE, callParam))
            {
                LOG4CXX_TRACE(gLogger, "err:\taccount=" << acct << "\torigcaller=" << caller  << "\torigcalled=" << called );
                esl_execute(pHandle, "hangup", NULL, NULL);
                esl_disconnect(pHandle);
                free(calluuid);
                return NULL;
            }

            if (callParam.begin()->nTimeout <= 0)
            {
                LOG4CXX_TRACE(gLogger, "err:timeout=" << callParam.begin()->nTimeout << "\taccount=" << acct << "\torigcaller=" << caller  << "\torigcalled=" << called );
                esl_execute(pHandle, "hangup", NULL, NULL);
                esl_disconnect(pHandle);
                free(calluuid);
                return NULL;
            }

            int n = 0;
            stringstream ss;

            for (vector<call_param_t>::iterator it = callParam.begin(); it != callParam.end(); ++it)
            {
                if (n > 0)
                {
                    ss << "|";
                }

                ss << "[execute_on_answer=\'sched_hangup +" << it->nTimeout << " alloted_timeout\',orig_caller=" << *iter << ",orig_called=" << *iter << ",absolute_codec_string=\'" << it->codec << "\',origination_caller_id_number=" << it->caller << ",origination_caller_id_name=" << it->caller << "]sofia/external/" << it->called << "@" << it->server;
                n++;
            }

            esl_send_recv(pHandle, ("bgapi originate {calltype=6,ignore_early_media=true,proxy_media=false,jitterbuffer_msec=180,call_timeout=50,orig_acct=" + acct + "}" + ss.str() + " &conference(" + caller + "@default)\nevent-lock:true").c_str());
        }

        //confname@profilename+[conference pin number]+flags{mute|deaf|waste|moderator}
        esl_execute(pHandle, "set", ("my_conference=" + caller + "@default+" + pin + "+flags{moderator|endconf}").c_str(), calluuid);

        if (esl_execute(pHandle, "transfer", "transfer XML conf", calluuid) != ESL_SUCCESS)
        {
            esl_execute(pHandle, "hangup", NULL, NULL);
        }

        free(calluuid);
        esl_disconnect(pHandle);
    }

    return NULL;
}


void * APR_THREAD_FUNC soft_flow(apr_thread_t*, void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    const char* pacct = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //主叫号码

    const char* pcalled = esl_event_get_header(pHandle->info_event, "Channel-Destination-Number");//被叫号码

    if (!(pacct && pcaller && pcalled))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL") << "\torigcalled=" << (pcalled ? pcalled : "NULL"));
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }



    string acct(pacct), caller(pcaller), called(pcalled);
    esl_execute(pHandle, "export", ("voip_call=" + called).c_str(), NULL);



    MakeCall(acct, caller, called, VOIP, pHandle);
    return NULL;
}


void * APR_THREAD_FUNC yuyue_flow(apr_thread_t*, void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    const char* pacct = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //主叫号码

    if (!(pacct && pcaller ))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL"));
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    string acct(pacct), caller(pcaller);
    vector<call_param_t> callParam;

    double fbalance;

    if (!getbalance(acct, caller, caller, 0, fbalance))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << acct << "\torigcaller=" << caller);
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    if (fbalance <= 0.0)
    {
        LOG4CXX_TRACE(gLogger, "err:timeout=" << callParam.begin()->nTimeout << "\taccount=" << acct << "\torigcaller=" << caller);
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL ;
    }

    char* const calluuid = strdup(esl_event_get_header(pHandle->info_event, "caller-unique-id"));
//    esl_execute(pHandle, "pre_answer", NULL, calluuid);
//    esl_execute(pHandle, "play_and_get_digits", "2 11 1 5000 # voice/cbcallbackb_tel_prompt.wav voice/operation_err.wav called \\d+", calluuid);

//    string getVar = "api uuid_getvar ";
//    esl_send_recv(pHandle, (getVar + calluuid + " called\nevent-lock:true").c_str());
//    const char* pcalled = NULL;

//    if (pHandle->last_sr_event != NULL)
//    {
//        pcalled = pHandle->last_sr_event->body;
//    }

    string called = "";

//    if (pcalled && pcalled[0] != '_')//!=_undef_
//    {
 //       called = pcalled;
 //   }

    esl_execute(pHandle, "playback", "voice/cbsubmitb_okbye.wav", calluuid);
    esl_execute(pHandle, "hangup", NULL, calluuid);
    esl_disconnect(pHandle);
    LOG4CXX_TRACE(gLogger, "called=" << called);
    free(calluuid);
    insertCallback(acct, caller, called);

    return NULL;
}
string getVar(esl_handle_t* pHandle, char* calluuid)
{
    string getVar = "api uuid_getvar ";
    esl_send_recv(pHandle, (getVar + calluuid + " inputvar\nevent-lock:true").c_str());
    const char* pVar = NULL;

    if (pHandle->last_sr_event != NULL)
    {
        pVar = pHandle->last_sr_event->body;
    }

    string called = "";

    if (pVar && pVar[0] != '_')//!=_undef_
    {
        called = pVar;
    }

    return called;
}
void voice_float(esl_handle_t* pHandle, float fbalance);
//充值
void * APR_THREAD_FUNC chongzhi_flow(apr_thread_t*, void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;
	bool exit = false;
    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    const char* pacct = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //主叫号码

    const char* pcalled = esl_event_get_header(pHandle->info_event, "Channel-Destination-Number");//被叫号码

    char* const calluuid = esl_event_get_header(pHandle->info_event, "caller-unique-id");

    if (!(pacct && pcaller && pcalled))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL") << "\torigcalled=" << (pcalled ? pcalled : "NULL"));
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }
	//获取选项 1#=本机充值 2#=绑定集团号码
    esl_execute(pHandle, "play_and_get_digits", "1 12 3 30000 # voice/option.wav voice/operation_err.wav inputvar \\d*", NULL);
    string option = getVar(pHandle, calluuid);
	//如果按下2则进入绑定流程
    LOG4CXX_TRACE(gLogger, "option:" << option );
	if (strcmp(option.c_str(), "2") == 0)
    {
		//播放请输入绑定号码语音并接受输入的号码 错误语音应该是号码输入错误
		esl_execute(pHandle, "play_and_get_digits", "4 8 3 30000 # voice/bindshorttip.wav voice/operation_err.wav inputvar \\d*", NULL);
		string input = getVar(pHandle, calluuid);
		
		if (input.empty())
		{
			//提示号码输入错误
			esl_execute(pHandle, "playback", "voice/operation_err.wav", NULL);
			esl_execute(pHandle, "hangup", NULL, NULL);
			esl_disconnect(pHandle);
			return NULL;
		}
		
		//此处还应播放 您输入的绑定号码是
		//code
		//播放输入的小号
		for (int i = 0; i < input.length(); i++)
		{
			esl_execute(pHandle, "playback", ("yuyue/" + input.substr(i, 1) + ".wav").c_str(), NULL);
		}
		
		//提示按1#绑定 其他为重新输入
		esl_execute(pHandle, "play_and_get_digits", "1 8 3 30000 # voice/bindshortconfig.wav voice/operation_err.wav inputvar \\d*", NULL);
		string input1 = getVar(pHandle, calluuid);
		if (strcmp(input1.c_str(), "1") == 0)
		{
			//按下确认
			
		}else{
			input = input1;
		}
			//开始绑定
			if (bindshort(pacct,input))
			{
				//绑定成功
				esl_execute(pHandle, "playback", "voice/bindshortok.wav", NULL);
				esl_execute(pHandle, "hangup", NULL, NULL);
				esl_disconnect(pHandle);
				return NULL;
			}else{
				//绑定失败
				esl_execute(pHandle, "playback", "voice/binderr.wav", NULL);
				esl_execute(pHandle, "hangup", NULL, NULL);
				esl_disconnect(pHandle);
				return NULL;
			}
			LOG4CXX_TRACE(gLogger, "bindshort:" << input );
			esl_execute(pHandle, "hangup", NULL, NULL);
			esl_disconnect(pHandle);
			return NULL;
		
    }
	//充值流程
	//esl_execute(pHandle, "play_and_get_digits", "1 12 3 30000 # voice/callerid_prompt.wav voice/operation_err.wav inputvar \\d*", NULL);
    string fillacct = option;
	esl_execute(pHandle, "play_and_get_digits", "5 120 3 30000 # voice/card_prompt.wav voice/operation_err.wav inputvar \\d+", NULL);
    string card = getVar(pHandle, calluuid);
    esl_execute(pHandle, "play_and_get_digits", "5 120 3 30000 # voice/pass_prompt.wav voice/operation_err.wav inputvar \\d+", NULL);
    string pwd = getVar(pHandle, calluuid);

    if (card.empty() || pwd.empty())
    {
        esl_execute(pHandle, "playback", "voice/carderr_prompt.wav", NULL);
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    string caller = pcaller;

    if (fillacct.empty() || strcmp(fillacct.c_str(), "1") == 0)
    {
        fillacct = caller;
    }

    float card_value, fbalance;

    if (!charged(caller, fillacct, card, pwd, card_value, fbalance))
    {
        esl_execute(pHandle, "playback", "voice/carderr_prompt.wav", NULL);
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    esl_execute(pHandle, "playback", "voice/voucher_chong_ok.wav", NULL);
    voice_float(pHandle, card_value);
    esl_execute(pHandle, "playback", "voice/voucher_yu.wav", NULL);
    voice_float(pHandle, fbalance);
    esl_execute(pHandle, "hangup", NULL, NULL);
    esl_disconnect(pHandle);
    return NULL;
}
void voice_float(esl_handle_t* pHandle, float fbalance)
{
    stringstream ss;
    int qian = fbalance / 1000;
    fbalance -= qian * 1000;
    LOG4CXX_TRACE(gLogger, "voice_float:" << fbalance );
    if (qian > 0)
    {
        ss.str("");
        ss << "yuyue/" << qian << ".wav";
        esl_execute(pHandle, "playback", ss.str().c_str(), NULL);
        esl_execute(pHandle, "playback", "yuyue/qian_chinese_.wav", NULL);
    }


    int bai = fbalance / 100;
    fbalance -= bai * 100;

    if (bai > 0)
    {
        ss.str("");
        ss << "yuyue/" << bai << ".wav";
        esl_execute(pHandle, "playback", ss.str().c_str(), NULL);
        esl_execute(pHandle, "playback", "yuyue/bai_chinese_.wav", NULL);
    }

    int shi = fbalance / 10;
    fbalance -= shi * 10;

    if (shi > 0)
    {
        ss.str("");
        ss << "yuyue/" << shi << ".wav";
        esl_execute(pHandle, "playback", ss.str().c_str(), NULL);
        esl_execute(pHandle, "playback", "yuyue/shi_chinese_.wav", NULL);
    }

    int yuan = fbalance;
    fbalance -= yuan;

    if (yuan > 0)
    {
        ss.str("");
        ss << "yuyue/" << yuan << ".wav";
        esl_execute(pHandle, "playback", ss.str().c_str(), NULL);
    }

    esl_execute(pHandle, "playback", "yuyue/yuan_chinese_.wav", NULL);
    int jiao = fbalance * 10;
    fbalance = fbalance * 10 - jiao;

    if (jiao > 0)
    {
        ss.str("");
        ss << "yuyue/" << jiao << ".wav";
        esl_execute(pHandle, "playback", ss.str().c_str(), NULL);
        esl_execute(pHandle, "playback", "yuyue/jiao_chinese_.wav", NULL);
    }

    int fen = fbalance * 10;

    if (fen > 0)
    {
        ss.str("");
        ss << "yuyue/" << fen << ".wav";
        esl_execute(pHandle, "playback", ss.str().c_str(), NULL);
        esl_execute(pHandle, "playback", "yuyue/fen_chinese_.wav", NULL);
    }
}



void voice_balance(esl_handle_t* pHandle,string& acctname)
{
    const char* pacct = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //计费账户
	pacct = acctname.c_str();
    if (!(pacct))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") );
        return;
    }

    string acct(pacct);
    double fbalance;

    if (getbalance(acct, acct, acct, 0, fbalance))
    {

        esl_execute(pHandle, "playback", "yuyue/money_chinese_.wav", NULL);
        voice_float(pHandle, fbalance);
    }
}
//直播
void * APR_THREAD_FUNC direct_flow(apr_thread_t*, void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }
	//voice_balance(pHandle);
    const char* pacct = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //主叫号码
	string acctname  = pacct;
    //const char* pcalled = esl_event_get_header(pHandle->info_event, "Channel-Destination-Number");//被叫号码
	if(strlen(pacct) < 11)
	{
	//小号 则转换
		string acct = pacct;
		if (!shorttoacctname(acct,acctname))
		{
			LOG4CXX_TRACE(gLogger, "shorttoacctname=false");
			esl_execute(pHandle, "hangup", NULL, NULL);
			esl_disconnect(pHandle);
			return NULL;
		}else{
			LOG4CXX_TRACE(gLogger, "shorttoacctname=true");
			pacct = acctname.c_str();
			pcaller = acctname.c_str();
		}
	}
	LOG4CXX_TRACE(gLogger, "pacct = " << pacct << "\t len:" << strlen(pacct));
	LOG4CXX_TRACE(gLogger, "shorttoacctname ,pacct = " << pacct << "\t acctname=" << acctname);
    char* const calluuid = strdup(esl_event_get_header(pHandle->info_event, "caller-unique-id"));

    esl_execute(pHandle, "answer", NULL, calluuid);
	const char* pcalled = NULL;
	
	/* esl_execute(pHandle, "play_and_get_digits", "2 15 1 2000 # voice/cbcallbackb_tel_prompt1.wav voice/operation_err.wav called ^[0-9]+$", calluuid);
	string input1 = getVar(pHandle, calluuid);
		if (strcmp(input1.c_str(), "2") == 0)
		{
			//包余额
			string ipacct = pacct;
			voice_balance(pHandle,ipacct);
			esl_execute(pHandle, "hangup", NULL, NULL);
			esl_disconnect(pHandle);
			return NULL;
		}
    

    esl_send_recv(pHandle, (getVar + calluuid + " called\nevent-lock:true").c_str());

    

    if (pHandle->last_sr_event != NULL)
    {
        pcalled = pHandle->last_sr_event->body;
    }
	
	
	if (!(pacct && pcaller && pcalled && pcalled[0] != '_'))
    {
		string ipacct = pacct;
		voice_balance(pHandle,ipacct);
        LOG4CXX_TRACE(gLogger,"user not input,now voice_balance");
	}else{
		string acct(pacct), caller(pcaller), called(pcalled);
		LOG4CXX_TRACE(gLogger,"acct = " << acct << "\t caller = " << caller);
		MakeCall(acct, caller, called, DIRECT, pHandle);
		return NULL;
	} */
    esl_execute(pHandle, "play_and_get_digits", "1 15 3 30000 # voice/cbcallbackb_tel_prompt1.wav voice/operation_err.wav called ^[0-9]+$", calluuid);

		//string input1 = getVar(pHandle, calluuid);
		
	string getVar = "api uuid_getvar ";	
    esl_send_recv(pHandle, (getVar + calluuid + " called\nevent-lock:true").c_str());


    if (pHandle->last_sr_event != NULL)
    {
        pcalled = pHandle->last_sr_event->body;
    }
		if (strcmp(pcalled, "2") == 0)
		{
			//包余额
			string ipacct = pacct;
			voice_balance(pHandle,ipacct);
			esl_execute(pHandle, "hangup", NULL, NULL);
			esl_disconnect(pHandle);
			return NULL;
		}
	
	  LOG4CXX_TRACE(gLogger,"input:pacct=" << pacct << "\tpcaller=" << pcaller << "\tpcalled=" << pcalled << "\tpcalled[0]=" << pcalled[0] );
    if (!(pacct && pcaller && pcalled && pcalled[0] != '_'))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL") << "\torigcalled=" << (pcalled ? pcalled : "NULL"));
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    string acct(pacct), caller(pcaller), called(pcalled);
    LOG4CXX_TRACE(gLogger,"acct = " << acct << "\t caller = " << caller);
    MakeCall(acct, caller, called, DIRECT, pHandle);
    return NULL;
}
//亲亲号直播
void * APR_THREAD_FUNC qinqindirect_flow(apr_thread_t*, void* pData)
{
	thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }
	//voice_balance(pHandle);
    const char* pacct = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //主叫号码
	const char* add_conf = esl_event_get_header(pHandle->info_event, "variable_add_conf");//落地编码
	char* const calluuid = strdup(esl_event_get_header(pHandle->info_event, "caller-unique-id"));
	string acctname  = pacct;
    //const char* pcalled = esl_event_get_header(pHandle->info_event, "Channel-Destination-Number");//被叫号码
	if(strlen(pacct) < 11)
	{
	//小号 则转换
		string acct = pacct;
		if (!shorttoacctname(acct,acctname))
		{
			LOG4CXX_TRACE(gLogger, "shorttoacctname=false");
			esl_execute(pHandle, "hangup", NULL, NULL);
			esl_disconnect(pHandle);
			return NULL;
		}else{
			LOG4CXX_TRACE(gLogger, "shorttoacctname=true");
			pacct = acctname.c_str();
			pcaller = acctname.c_str();
		}
	}
    esl_execute(pHandle, "answer", NULL, calluuid);
		//获取是否绑定快捷号
		string quicknum = "";
		string sipnum = add_conf;
		if (!getquicknum(pacct,sipnum,quicknum))
		{
			const char* pcalled = NULL;
			//没有绑定 请输入被叫
			esl_execute(pHandle, "play_and_get_digits", "1 15 3 30000 # voice/cbcallbackb_tel_prompt1.wav voice/operation_err.wav called ^[0-9]+$", calluuid);
			string getVar = "api uuid_getvar ";	
			esl_send_recv(pHandle, (getVar + calluuid + " called\nevent-lock:true").c_str());
			if (pHandle->last_sr_event != NULL)
			{
				pcalled = pHandle->last_sr_event->body;
			}
			if (!(pacct && pcaller && pcalled && pcalled[0] != '_'))
			{
				LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL") << "\torigcalled=" << (pcalled ? pcalled : "NULL"));
				esl_execute(pHandle, "hangup", NULL, NULL);
				esl_disconnect(pHandle);
				return NULL;
			}
			
			//外呼
			string acct(pacct), caller(pcaller), called(pcalled);
			//插入记录
			bindqinqin(acct,called,sipnum);
			LOG4CXX_TRACE(gLogger,"acct = " << acct << "\t caller = " << caller);
			MakeCall(acct, caller, called, DIRECT, pHandle);
			return NULL;
		}else{
			LOG4CXX_TRACE(gLogger, "getquicknum=true,quick=" << quicknum);
			string acct1(pacct), caller1(pcaller);
			MakeCall(acct1, caller1, quicknum, DIRECT, pHandle);
			return NULL;
		}
}
//预约报余额
void * APR_THREAD_FUNC baorealyuyue_flow(apr_thread_t*, void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }
	
    const char* pacct = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //主叫号码

    if (!(pacct && pcaller ))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL"));
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    string acct(pacct), caller(pcaller);
    vector<call_param_t> callParam;

    double fbalance;

    if (!getbalance(acct, caller, caller, 0, fbalance))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << acct << "\torigcaller=" << caller);
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    if (fbalance <= 0.0)
    {
        LOG4CXX_TRACE(gLogger, "err:timeout=" << callParam.begin()->nTimeout << "\taccount=" << acct << "\torigcaller=" << caller);
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL ;
    }
	string ipacct = pacct;
	voice_balance(pHandle,ipacct);
	//voice_balance(pHandle);

    char* const calluuid = strdup(esl_event_get_header(pHandle->info_event, "caller-unique-id"));
   // esl_execute(pHandle, "pre_answer", NULL, calluuid);
  //  esl_execute(pHandle, "play_and_get_digits", "2 11 1 5000 # voice/cbcallbackb_tel_prompt.wav voice/operation_err.wav called \\d+", calluuid);

  //  string getVar = "api uuid_getvar ";
  //  esl_send_recv(pHandle, (getVar + calluuid + " called\nevent-lock:true").c_str());
  //  const char* pcalled = NULL;

    //if (pHandle->last_sr_event != NULL)
   // {
   //     pcalled = pHandle->last_sr_event->body;
   // }

    string called = "";

    //if (pcalled && pcalled[0] != '_')//!=_undef_
    //{
    //    called = pcalled;
    //}

    esl_execute(pHandle, "playback", "voice/cbsubmitb_okbye.wav", calluuid);
    esl_execute(pHandle, "hangup", NULL, calluuid);
    esl_disconnect(pHandle);
    LOG4CXX_TRACE(gLogger, "called=" << called);
    free(calluuid);
    insertCallback(acct, caller, called);

    return NULL;
}
void * APR_THREAD_FUNC chaxun_flow(apr_thread_t*, void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }
	const char* pacct = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //计费账户
	string ipacct = pacct;
	voice_balance(pHandle,ipacct);
    //voice_balance(pHandle);
    esl_execute(pHandle, "hangup", NULL, NULL);
    esl_disconnect(pHandle);
    return NULL;
}

bool checkPriv(thread_param_t* pParam)
{
    char* pAddr = NULL;
    apr_sockaddr_t *sa = NULL;
    apr_socket_addr_get(&sa, APR_REMOTE, pParam->client);
    apr_sockaddr_ip_get(&pAddr, sa);

    bool bIn = true;

    if (pParam->ipsubs.size() > 0)
    {
        //设置了客户端限制,检测是否客户端限制内
        bIn = false;
        vector<apr_ipsubnet_t*>::iterator it = pParam->ipsubs.begin();

        for (; it != pParam->ipsubs.end(); ++it)
        {
            if (apr_ipsubnet_test(*it, sa) > 0)
            {
                bIn = true;
                break;
            }
        }

        if (!bIn)
        {
            LOG4CXX_INFO(gLogger, pAddr << "is invalid,close");
        }
    }

    return bIn;
}

esl_handle_t* GetESLHandle(esl_handle_t* pHandle, thread_param_t* pParam)
{
    esl_socket_t client_sock = *(esl_socket_t*)((char*)(pParam->client) + sizeof(apr_pool_t*) / sizeof(char));

    apr_sockaddr_t *sa = NULL;
    apr_socket_addr_get(&sa, APR_REMOTE, pParam->client);

    if (esl_attach_handle(pHandle, client_sock, &(sa->sa.sin)) == ESL_SUCCESS)
    {
        return pHandle;
    }

    return NULL;
}


void MakeCall(string& acct, string& caller, string& called, CALL_TYPE calltype, esl_handle_t* pHandle)
{
    char* const calluuid = strdup(esl_event_get_header(pHandle->info_event, "caller-unique-id"));
    vector<call_param_t> callParam;

    if (!getCallParam(acct, caller, called, calltype, callParam))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << acct << "\torigcaller=" << caller  << "\torigcalled=" << called );
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        free(calluuid);
        return;
    }

    if (callParam.begin()->nTimeout <= 0)
    {
        LOG4CXX_TRACE(gLogger, "err:timeout=" << callParam.begin()->nTimeout << "\taccount=" << acct << "\torigcaller=" << caller  << "\torigcalled=" << called );
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        free(calluuid);
        return;
    }

    esl_execute(pHandle, "export", "proxy_media=false", calluuid);
    esl_execute(pHandle, "export", "jitterbuffer_msec=180", calluuid);
    esl_execute(pHandle, "export", "call_timeout=50", calluuid);
    esl_execute(pHandle, "export", ("nolocal:orig_acct=" + acct).c_str(), calluuid);
    esl_execute(pHandle, "export", ("nolocal:orig_caller=" + caller).c_str(), calluuid);
    esl_execute(pHandle, "export", ("nolocal:orig_called=" + called).c_str(), calluuid);

    int n = 0;
    stringstream ss;

    for (vector<call_param_t>::iterator it = callParam.begin(); it != callParam.end(); ++it)
    {
        if (n == 0)
        {
            if (it->bRingFlag > 0)
            {
                esl_execute(pHandle, "export", "ignore_early_media=false", calluuid);
            }
            else
            {
                esl_execute(pHandle, "export", "ignore_early_media=true", calluuid);
            }

        }

        if (n > 0)
        {
            ss << "|";
        }


        ss << "[ignore_early_media=" << (it->bRingFlag > 0 ? "false" : "true") << ",calltype=" << (int)calltype << ",execute_on_answer=\'sched_hangup +" << it->nTimeout << " alloted_timeout\',origination_caller_id_name=" << it->caller << ",origination_caller_id_number=" << it->caller << ",absolute_codec_string=\'" << it->codec << "\']"
        << "sofia/external/" << it->called << "@" << it->server;
        n++;
    }

    string strTmp = ss.str();
    n = 0;

    while (strTmp.length() > 400)
    {
        ss.str("");
        string subStr = strTmp.substr(0, 400);
        strTmp = strTmp.substr(400);
        ss << "bg" << n++ << "=" << subStr;
        esl_execute(pHandle, "set", ss.str().c_str(), calluuid);
        LOG4CXX_TRACE(gLogger, ss.str());
    }

    ss.str("");
    ss << "bg" << n << "=" << strTmp;
    esl_execute(pHandle, "set", ss.str().c_str(), calluuid);
    LOG4CXX_TRACE(gLogger, ss.str());

    if (calltype == VOIP)
    {
        if (esl_execute(pHandle, "transfer", "transfer_voip XML default", calluuid) != ESL_SUCCESS)
        {
            esl_execute(pHandle, "hangup", NULL, NULL);
        }
    }
    else
    {
        if (esl_execute(pHandle, "transfer", "transfer_callback XML default", calluuid) != ESL_SUCCESS)
        {
            esl_execute(pHandle, "hangup", NULL, NULL);
        }
    }
    esl_execute(pHandle, "export", "test=test", calluuid);
    LOG4CXX_TRACE(gLogger, caller << "------------->" << called << "\t" << ss.str());
    free(calluuid);
    esl_disconnect(pHandle);

}

bool init_socket(apr_socket_t** psocket, int nPort, const char* addr, apr_pool_t* pool)
{
    apr_sockaddr_t *    sa = NULL;
    apr_status_t rst = apr_socket_create(psocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, pool);

    if (rst != APR_SUCCESS)
    {
        LOG4CXX_WARN(gLogger, "apr_socket_create error");
        return false;
    }

    rst = apr_sockaddr_info_get(&sa, addr, AF_UNSPEC, nPort, APR_IPV4_ADDR_OK, pool);

    if (rst != APR_SUCCESS)
    {
        LOG4CXX_WARN(gLogger, "apr_sockaddr_info_get error");
        apr_socket_close(*psocket);
        *psocket = NULL;
        return false;
    }

    if (apr_socket_bind(*psocket, sa) != APR_SUCCESS)
    {
        LOG4CXX_WARN(gLogger, "apr_socket_bind error");
        apr_socket_close(*psocket);
        *psocket = NULL;
        return false;
    }

    apr_socket_opt_set(*psocket, APR_SO_REUSEADDR, 1);

    if (apr_socket_listen(*psocket, SOMAXCONN) != APR_SUCCESS)
    {
        LOG4CXX_WARN(gLogger, "apr_socket_listen error");
        apr_socket_close(*psocket);
        *psocket = NULL;
        return false;
    }

    return true;
}

void * APR_THREAD_FUNC auth_flow(apr_thread_t*, void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    const char* pacct = esl_event_get_header(pHandle->info_event, "variable_orig_acct"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "variable_orig_caller"); //主叫号码

    const char* pcalled = esl_event_get_header(pHandle->info_event, "variable_orig_called");//被叫号码


    if (!(pacct && pcaller && pcalled))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL") << "\torigcalled=" << (pcalled ? pcalled : "NULL"));
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }



    string acct(pacct), caller(pcaller), called(pcalled);
    //esl_execute(pHandle, "export", ("voip_call=" + called).c_str(), NULL);
    esl_execute(pHandle, "playback", "voice/auth.wav", NULL);
    string  authInput;
    char* const calluuid = strdup(esl_event_get_header(pHandle->info_event, "caller-unique-id"));

    for (int i = 0; i < called.length(); i++)
    {
        esl_execute(pHandle, "playback", ("yuyue/" + called.substr(i, 1) + ".wav").c_str(), NULL);
    }

    esl_execute(pHandle, "play_and_get_digits", "2 10 1 5000 # voice/space.wav voice/operation_err.wav authcode \\d+", NULL);

    string getVar = "api uuid_getvar ";
    esl_send_recv(pHandle, (getVar + calluuid + " authcode\nevent-lock:true").c_str());

    if (pHandle->last_sr_event != NULL)
    {
        authInput = pHandle->last_sr_event->body;
    }

    if (auth_voip(acct, caller, authInput))
    {
        esl_execute(pHandle, "playback", "voice/bindok.wav", NULL);
    }
    else
    {
        esl_execute(pHandle, "playback", "voice/bindfailed.wav", NULL);
    }

    esl_execute(pHandle, "hangup", NULL, NULL);
    esl_disconnect(pHandle);
    //MakeCall(acct, caller, called, VOIP, pHandle);
    return NULL;
}

void * APR_THREAD_FUNC yuyue_authbind_flow(apr_thread_t*, void* pData)
{
    thread_param_t* pParam = (thread_param_t*)pData;

    if (!checkPriv(pParam))
    {
        return NULL;
    }

    esl_handle_t handle = {{0}};
    esl_handle_t* pHandle = GetESLHandle(&handle, pParam);

    if (pHandle == NULL)
    {
        return NULL;
    }

    if (!pHandle->info_event)
    {
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    const char* pacct = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //计费账户

    const char* pcaller = esl_event_get_header(pHandle->info_event, "caller-caller-id-number"); //主叫号码

    if (!(pacct && pcaller ))
    {
        LOG4CXX_TRACE(gLogger, "err:\taccount=" << (pacct ? pacct : "NULL") << "\torigcaller=" << (pcaller ? pcaller : "NULL"));
        esl_execute(pHandle, "hangup", NULL, NULL);
        esl_disconnect(pHandle);
        return NULL;
    }

    string acct(pacct), caller(pcaller);
    esl_execute(pHandle, "pre_answer", NULL, NULL);
    esl_execute(pHandle, "playback", "voice/authStart.wav", NULL);
    esl_execute(pHandle, "hangup", NULL, NULL);
    esl_disconnect(pHandle);
    insertAuth(acct, caller);

    return NULL;
}

bool bindPort2flow(string addr, int port, string priv, apr_pool_t* main_pool, apr_thread_start_t flow, vector<apr_pollfd_t*>& vFlows)
{
    apr_socket_t* listenfd = NULL;
    apr_pool_t* client_Pool = NULL;

    thread_param_t* threadParam = new thread_param_t();
    threadParam->func = flow;

    if (apr_pool_create(&client_Pool, main_pool) != APR_SUCCESS)
    {
        threadParam->pool = client_Pool;
    }
    else
    {
        threadParam->pool = main_pool;
    }

    if (priv.length() > 0)
    {
        string delimiter(",");
        const vector<string>& clientlist = split(priv, delimiter);

        for (vector<string>::const_iterator iter = clientlist.begin(); iter != clientlist.end(); ++iter)
        {
            char* pIp = strdup((*iter).c_str());
            char* pMask = strchr(pIp, '/');

            if (pMask != NULL)
            {
                *pMask++ = '\0';
            }

            apr_ipsubnet_t* ipsub;

            if (apr_ipsubnet_create(&ipsub, pIp, pMask, main_pool) == APR_SUCCESS)
            {
                threadParam->ipsubs.push_back(ipsub);
                LOG4CXX_INFO(gLogger, "add client addr : " << pIp << " mask " << (pMask ? pMask : "255.255.255.255"));
            }

            free(pIp);
        }
    }

    if (!init_socket(&listenfd, port, addr.c_str(), threadParam->pool))
    {
        delete threadParam;
        return false;
    }

    apr_pollfd_t* pfd = new apr_pollfd_t();
    pfd->p = threadParam->pool;
    pfd->desc_type = APR_POLL_SOCKET;
    pfd->reqevents = APR_POLLIN;
    pfd->desc.s = listenfd;
    pfd->client_data = (void*) threadParam;
    vFlows.push_back(pfd);
    return true;
}



#ifndef _DEBUG
int localMain(int argc, char* argv[]);
int main(int argc, char *argv[])
{
    if (init_daemon(argc, argv, localMain) < 0)
    {
        return 0;
    }

    return 0;
}
int localMain(int argc, char* argv[])
#else
int main(int argc, char *argv[])
#endif
{
    signal(SIGUSR1, sighandler);
    apr_initialize();

    CIniFile config;
    string strCfgPath("/etc/fsroute.ini");

    if (argc >= 2)
    {
        strCfgPath = argv[1];
    }

    ostringstream ss;

    config.SetPath(strCfgPath);
    config.ReadFile();
    PropertyConfigurator::configure(strCfgPath);


    const string bindIp = config.GetValue("route", "bindaddr", "0.0.0.0");

    const int ncbbindPort = config.GetValueI("route", "callback", 1201);
    const int ncfbindPort = config.GetValueI("route", "conference", 1202);
    const int nsfbindPort = config.GetValueI("route", "softport", 1203);
//baorealyuyue_flow
    const int nyybindPort = config.GetValueI("route", "yuyue", 1204);
	const int nrealyuyuePort = config.GetValueI("route", "realyuyue", 1210);
    const int nbaorealyuyuePort = config.GetValueI("route", "baorealyuyue", 1211);
    const int nczbindPort = config.GetValueI("route", "chongzhi", 1205);
    const int ncxbindPort = config.GetValueI("route", "chaxun", 1206);

    const int nauthbindPort = config.GetValueI("route", "auth", 1207);
    const int nyyauthbindPort = config.GetValueI("route", "yuyueauth", 1208);

    const int ndirectPort = config.GetValueI("route", "direct", 1209);
//亲亲号
	const int nqinqindirectPort = config.GetValueI("route", "qinqindirect", 1212);
	
    const string strCbClient = config.GetValue("route", "cbclient", "");
    const string strCfClient = config.GetValue("route", "cfclient", "");
    const string strSfClient = config.GetValue("route", "sfclient", "");
	const string strrealyuyueClient = config.GetValue("route", "realyyclient", "");
    const string stryyClient = config.GetValue("route", "yyclient", "");
	const string strrealyyclient = config.GetValue("route", "baorealyyclient", "");
    const string strcxClient = config.GetValue("route", "cxclient", "");
    const string strczClient = config.GetValue("route", "czclient", "");
    const string strauthClient = config.GetValue("route", "authclient", "");
    const string strauthyyClient = config.GetValue("route", "authyyclient", "");
    const string strDirectClient = config.GetValue("route", "directclient", "");
//亲亲
	const string strqinqindirectClient = config.GetValue("route", "qinqindirectclient", "");

    const int nMaxSize = config.GetValueI("route", "maxsize", 100);
    const int nThreadPool = config.GetValueI("route", "threads", 500);

    LOG4CXX_TRACE(gLogger, "config=" << strCfgPath << "\tbindip=" << bindIp
                  << "\tcallback route bindport=" << ncbbindPort << "\tcallback server=" << strCbClient
                  << "\tconference route bindport=" << ncfbindPort << "\tconference server=" << strCfClient
                  << "\tsoft route bindport=" << nsfbindPort << "\tsoft phone server=" << strSfClient << "\tThreadpool=" << nThreadPool);




    //initalize线程池，数据库池
    apr_thread_pool_t *thrp;
    apr_pool_t *main_Pool;

    if (apr_pool_create(&main_Pool, NULL) != APR_SUCCESS)
    {
        LOG4CXX_WARN(gLogger, "apr_pool_create error");
        apr_terminate();
        return -1;
    }


    apr_allocator_t* my_alloc = apr_pool_allocator_get(main_Pool);
    apr_size_t maxsize = nMaxSize;
    apr_allocator_max_free_set(my_alloc, maxsize*1024*1024);
    LOG4CXX_INFO(gLogger, "init memory pool ok");


    if (apr_thread_pool_create(&thrp, nThreadPool, nThreadPool, main_Pool) != APR_SUCCESS)
    {
        LOG4CXX_WARN(gLogger, "apr_thread_pool_create error,thread pool=" << nThreadPool);
        apr_pool_destroy(main_Pool);
        apr_terminate();
        return -2;//线程池创建失败
    }

    LOG4CXX_INFO(gLogger, "init thread pool ok");


    if (!initDBS(config, "route-db", main_Pool))
    {
        LOG4CXX_WARN(gLogger, "init dbs error");
        apr_pool_destroy(main_Pool);
        apr_terminate();
        return -3;//数据库池创建失败
    }

    LOG4CXX_INFO(gLogger, "init dbs pool ok");

#ifdef _DEBUG
    esl_global_set_default_logger(7);
    esl_global_set_logger(default_logger);
#else
    esl_global_set_logger(NULL);
#endif



    //创建监听socket
    apr_pollset_t *pollset;
    const apr_pollfd_t *hot_files;
    apr_int32_t num;

    vector<apr_pollfd_t*> vFlows;
    vector<apr_pollfd_t*>::iterator iter;


    if ((!bindPort2flow(bindIp, ncbbindPort, strCbClient, main_Pool, callback_flow, vFlows))
            || (!bindPort2flow(bindIp, ncfbindPort, strCfClient, main_Pool, conference_flow, vFlows))
            || (!bindPort2flow(bindIp, nsfbindPort, strSfClient, main_Pool, soft_flow, vFlows))
            || (!bindPort2flow(bindIp, nyybindPort, stryyClient, main_Pool, yuyue_flow, vFlows))
            || (!bindPort2flow(bindIp, nczbindPort, strczClient, main_Pool, chongzhi_flow, vFlows))
            || (!bindPort2flow(bindIp, ncxbindPort, strcxClient, main_Pool, chaxun_flow, vFlows))
            || (!bindPort2flow(bindIp, nauthbindPort, strauthClient, main_Pool, auth_flow, vFlows))
            || (!bindPort2flow(bindIp, nyyauthbindPort, strauthyyClient, main_Pool, yuyue_authbind_flow, vFlows))
            || (!bindPort2flow(bindIp, ndirectPort, strDirectClient, main_Pool, direct_flow, vFlows))
			|| (!bindPort2flow(bindIp, nrealyuyuePort, strrealyuyueClient, main_Pool, yuyue_flow, vFlows))s
			|| (!bindPort2flow(bindIp, nbaorealyuyuePort, strrealyyclient, main_Pool, baorealyuyue_flow, vFlows))
			|| (!bindPort2flow(bindIp, nqinqindirectPort, strqinqindirectClient, main_Pool, qinqindirect_flow, vFlows))
		)
    {
        goto clean;
    }

    num = vFlows.size();

    if (apr_pollset_create_ex(&pollset, num, main_Pool, APR_POLLSET_NOCOPY, APR_POLLSET_EPOLL) != APR_SUCCESS)
    {
        LOG4CXX_WARN(gLogger, "apr_pollset_create error");
        goto clean;
    }

    for (iter = vFlows.begin(); iter != vFlows.end(); ++iter)
    {
        if (apr_pollset_add(pollset, (*iter)) != APR_SUCCESS)
        {
            LOG4CXX_WARN(gLogger, "apr_pollset_add error");
            goto clean;
        }
    }

    //接收请求，进入线程调度
    while (gRunThread)
    {
        if (apr_pollset_poll(pollset, 1000, &num, &hot_files) == APR_SUCCESS)
        {
            for (int i = 0; i < num; i++)
            {
                if (apr_socket_accept(&((thread_param_t*)(hot_files[i].client_data))->client, hot_files[i].desc.s, ((thread_param_t*)(hot_files[i].client_data))->pool) == APR_SUCCESS)
                {
                    if (apr_thread_pool_push(thrp, ((thread_param_t*)(hot_files[i].client_data))->func, hot_files[i].client_data, APR_THREAD_TASK_PRIORITY_NORMAL, NULL) != APR_SUCCESS)
                    {
                        LOG4CXX_WARN(gLogger, "apr_thread_pool_push error");
                    }
                }
            }
        }
    }

clean:
    apr_pollset_destroy(pollset);
    {
        for (iter = vFlows.begin(); iter != vFlows.end(); ++iter)
        {
            apr_socket_close((*iter)->desc.s);
            delete (thread_param_t*)((*iter)->client_data);
            delete *iter;
        }
    }
    apr_thread_pool_destroy(thrp);
    destoryDBS();
    apr_pool_destroy(main_Pool);
    apr_terminate();
    return 0;
}


